home *** CD-ROM | disk | FTP | other *** search
- /*
- File: MemDebg.cpp
-
- Contains: Memory management debug routine implementations
-
- Owned by: Jens Alfke
- Owned by: Jens Alfke, Vincent Lo, Nick Pilch, Michael Burbidge
-
- Copyright: © 1993 - 1995 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- <23> 10/3/95 TJ Opps, I had left some code in that had been
- if defed out.
- <22> 10/3/95 TJ Changes done by RefBall Team
- <21> 8/8/95 TJ Declared FindLeaksProc extern C
- <20> 8/7/95 TJ Typecast &InitLeaksProc to
- (MMBlockInfoProc) for the MMWalkHeap call
- so it will compile with SCpp.
- <19> 8/4/95 DM Leak checking [1267956]
- <18> 6/21/95 JBS turn off heap validation for ∂SOM data xfer
- <17> 6/7/95 jpa Changed old (pre-SLIM) SOM includes to
- som.xh [1256901]
- <16> 5/4/95 jpa Added MMFindBlockContaining [1246077]
- <15> 12/20/94 jpa Add stub routines in non-debug config so
- library will build. [1188344]
- <14> 12/5/94 jpa Nuked errant pragma lib_export's. [1195676]
- <13> 10/24/94 jpa Constness [1194286]
- <12> 9/29/94 RA 1189812: Mods for 68K build.
- <11> 9/20/94 VL jpa: Fixed infinite recursion in heap
- validation.
- <10> 9/14/94 jpa Eliminated dependencies on rest of OpenDoc.
- OD-->MM. [1186692]
- <9> 9/9/94 jpa Made ODValidatePtr more robust.
- <8> 8/19/94 NP 1181622: Ownership fix.
- <7> 8/17/94 jpa Added ODWalkHeap, greatly improved
- ODValidateObject, and added debugging
- checks using the SOM-block flag. [1179567]
- <6> 8/8/94 jpa Added ODGetHeapInfo. [1179567]
- <5> 8/2/94 jpa Plenty more fixes to validation.
- <4> 7/26/94 jpa Got validation stuff to work again.
- <3> 6/18/94 MB Include MemDebgP.h
- <2> 6/10/94 MB Make it build
- <1> 6/9/94 MB first checked in
- <3> 5/27/94 jpa New exception support [1165267]
- <2> 5/27/94 MB #1162181: Fixed MMM integration bug
- <1> 5/27/94 MB first checked in
- To Do:
-
- In Progress:
-
- */
-
- #ifndef _MEMCNFIG_
- #include "MemCnfig.h"
- #endif
-
- #ifndef _MEMDEBG_
- #include "MemDebg.h"
- #endif
-
-
- #if MM_DEBUG
-
-
- #ifndef _MEMMGRPV_
- #include "MemMgrPv.h"
- #endif
-
- #ifndef _MEMHOOKS_
- #include "MemHooks.h"
- #endif
-
- #include <string.h>
-
- #ifndef __SOM__
- #include <som.xh>
- #endif
-
- #include <SOMObj.xh>
-
- #ifndef _CRAWL_
- #include "Crawl.h"
- #endif
-
- #ifndef __LOWMEM__
- #include <LowMem.h>
- #endif
-
-
- //==============================================================================
- // Global variable definitions
- //==============================================================================
-
- MMBoolean gValidate = 0;
- MMBoolean gHeapChecking = 0;
-
-
- //==============================================================================
- // Function definitions
- //==============================================================================
-
-
- //------------------------------------------------------------------------------
- // DoesHeapExist
- //------------------------------------------------------------------------------
-
- MMBoolean MMDoesHeapExist( MemHeap *heap )
- {
- if( ((MemoryHeap*)heap)->GetLocation()==kMMSysMemory )
- return kMMTrue; // A system heap might have been allocated by another process.
-
- for( MemoryHeap *h = MemoryHeap::GetFirstHeap(); h; h = h->GetNextHeap() )
- if( h == (MemoryHeap*)heap )
- return kMMTrue;
- return kMMFalse;
- }
-
- //------------------------------------------------------------------------------
- // MMBeginMemValidation
- //------------------------------------------------------------------------------
-
- void
- MMBeginMemValidation( )
- {
- MMValidateAllHeaps();
- if( gValidate==0 )
- for( MemoryHeap *h = MemoryHeap::GetFirstHeap(); h; h = h->GetNextHeap() ) {
- h->SetZapOnAllocate(kMMTrue);
- h->SetZapOnFree(kMMTrue);
- h->SetAutoValidation(kMMTrue);
- }
- gValidate++;
- }
-
- //------------------------------------------------------------------------------
- // MMEndMemValidation
- //------------------------------------------------------------------------------
-
- void
- MMEndMemValidation( )
- {
- if( gValidate<=0 ) {
- MM_WARN("Improper nesting of memory-validation calls");
- return;
- }
-
- MMValidateAllHeaps();
- gValidate--;
- if (gValidate==0)
- for( MemoryHeap *h = MemoryHeap::GetFirstHeap(); h; h = h->GetNextHeap() ) {
- h->SetZapOnAllocate(kMMFalse);
- h->SetZapOnFree(kMMFalse);
- h->SetAutoValidation(kMMFalse);
- }
- }
-
- //------------------------------------------------------------------------------
- // MMBeginHeapChecking
- //------------------------------------------------------------------------------
-
- void
- MMBeginHeapChecking( )
- {
- gHeapChecking++;
- MMBeginMemValidation();
- }
-
- //------------------------------------------------------------------------------
- // MMEndHeapChecking
- //------------------------------------------------------------------------------
-
- void
- MMEndHeapChecking( )
- {
- if( gHeapChecking<=0 ) {
- MM_WARN("Improper nesting of heap-checking calls");
- return;
- }
-
- gHeapChecking--;
- MMEndMemValidation();
- }
-
- //------------------------------------------------------------------------------
- // MMValidateHeap
- //------------------------------------------------------------------------------
-
- static Boolean
- HeapCheckProc( const void *blk, unsigned long /*size*/, Boolean isObject, void *refCon )
- {
- if( isObject ) {
- (*(MMULong*)refCon) ++; // Increment object count
- MMValidateObject((SOMObject*)blk);
- }
- return true;
- }
-
-
- MMBoolean
- MMValidateHeap( MemHeap *heapID, const void* ptr )
- {
- if (!heapID )
- heapID = MMGetDefaultHeap();
-
- MM_ASSERT(heapID);
-
- #if 0
- if (!MMDoesHeapExist(heapID)) {
- if( ptr )
- MM_WARN("%p's heap at %p is unknown", ptr,heapID);
- else
- MM_WARN("%p is not a known heap", heapID);
- return kMMFalse;
- }
- #endif
-
- MMULong objects = 0;
- ((MemoryHeap*)heapID)->Check(&HeapCheckProc,&objects);
-
- return kMMTrue;
- }
-
-
- //------------------------------------------------------------------------------
- // MMValidateAllHeaps
- //------------------------------------------------------------------------------
-
- MMBoolean
- MMValidateAllHeaps( )
- {
- MMBoolean result = kMMTrue;
- for( MemoryHeap *h = MemoryHeap::GetFirstHeap(); h; h = h->GetNextHeap() )
- if( !MMValidateHeap((MemHeap*)h) )
- result = kMMFalse;
- return result;
- }
-
-
- //------------------------------------------------------------------------------
- // MMValidatePtr
- //------------------------------------------------------------------------------
-
- MMBoolean
- MMValidatePtr( const void* p, MMBoolean validateHeap, const char *operation )
- {
- // If we could be sure that p were in the app zone, we could be more
- // stringent. But it might be in the System heap or in temp-mem.
-
- const char *err = BasicValidatePtr(p);
- if( !err ) {
- BestFitHeap *heap = (BestFitHeap*) gDefaultHeap->GetBlockHeap(p);
-
- #if 0
- if (!MMDoesHeapExist((MemHeap*)heap))
- if( operation )
- MM_WARN("%s(%p): block's heap %p is unknown", operation,p,heap);
- else
- MM_WARN("%p's heap %p is unknown", p,heap);
- #endif
-
- if( !heap->IsValidBlock(p) ) {
- err = "is invalid";
- if( somIsObj((void*)p) ) {
- MM_WARN("Invalid block %p is an object of class %s",
- p, ((SOMObject*)p)->somGetClassName() );
- }
- } else if( validateHeap && !MMValidateHeap((MemHeap*)heap,p) )
- return kMMFalse; // ODValidateHeap already warns the user
- else
- return kMMTrue;
- }
-
- if( operation )
- MM_WARN("%s(%p): ptr %s!",operation,p,err);
- else
- MM_WARN("Pointer %p %s!",p,err);
- return kMMFalse;
- }
-
-
- //------------------------------------------------------------------------------
- // MMValidateObject
- //------------------------------------------------------------------------------
-
- static MMBoolean
- BasicIsObject( const void *block )
- {
- // This is like MMIsObject but does not do any heap checking, which would
- // be fatal if MMValidateObject were already being called during a heap-check!
-
- MemoryHeap *heap = gDefaultHeap->GetBlockHeap(block);
- return heap ?heap->BlockIsObject(block) :kMMFalse;
- }
-
- MMBoolean
- MMValidateObject( const SOMObject *o )
- {
- // I mustn't check the heap, since I am called during heap checking!!
- if( !MMValidatePtr(o,kMMFalse,"MMValidateObject") )
- return kMMFalse;
-
- const char *err;
- if( !BasicIsObject(o) )
- err = "is not marked as an object in the heap";
- else if( !gHaveSOM || !somIsObj((SOMObject*)o) )
- err = "is not a SOM object";
- else
- return kMMTrue;
-
- MM_WARN("Object %p %s!", o, err);
- return kMMFalse;
- }
-
- //------------------------------------------------------------------------------
- // MMGetHeapInfo
- //------------------------------------------------------------------------------
-
- void
- MMGetHeapInfo( MemHeap *heapID,
- const char* *name, size_t *allocated, size_t *free,
- size_t *nBlocks, size_t *nObjects )
- {
- MemoryHeap *heap = (MemoryHeap*)( heapID ?heapID :MMGetDefaultHeap() );
-
- if( name ) *name = heap->GetDescription();
- if( allocated ) *allocated = heap->BytesAllocated();
- if( free ) *free = heap->BytesFree();
- if( nBlocks ) *nBlocks = heap->NumberAllocatedBlocks();
-
- if( nObjects ) {
- *nObjects = 0;
- heap->Check(&HeapCheckProc,&*nObjects);
- }
- }
-
-
- //------------------------------------------------------------------------------
- // MMWalkHeap
- //------------------------------------------------------------------------------
-
- struct HeapWalkData {
- MMBlockInfoProc proc;
- void *refCon;
- };
-
- static Boolean CallHeapWalkProc( void *blk, unsigned long size, Boolean isObject,
- void *refCon )
- {
- if( isObject )
- MMValidateObject((SOMObject*)blk);
- else
- MMValidatePtr(blk,false);
-
- HeapWalkData *data = (HeapWalkData*) refCon;
- return (data->proc) (blk, size, isObject, data->refCon);
- }
-
-
-
- void
- MMWalkHeap( MemHeap *heapID, MMBlockInfoProc proc, void *refCon )
- {
- MemoryHeap *heap = (MemoryHeap*)( heapID ?heapID :MMGetDefaultHeap() );
-
- HeapWalkData data;
- data.proc = proc;
- data.refCon = refCon;
- heap->Check((HeapWalkProc)CallHeapWalkProc,&data);
- }
-
- MMBoolean
- MMFindBlockContaining( const void *start, const void *end,
- const void* *blockStart, const void* *blockEnd )
- {
- const void *foo, *bar;
- if( !blockStart ) blockStart=&foo;
- if( !blockEnd ) blockEnd=&bar;
-
- if( end<start ) {
- const void *temp = end;
- end = start;
- start = temp;
- }
-
- MemoryHeap *heap = (MemoryHeap*)MMGetDefaultHeap();
- return heap->FindBlockContaining(start,end,*blockStart,*blockEnd);
- }
-
-
- MMBoolean
- MMValidateMemoryRange( const void *start, const void *end )
- {
- // Warn if memory range is in default heap but not entirely within a valid block:
- if( end<start ) {
- const void *temp = end;
- end = start;
- start = temp;
- }
- const void *blockStart, *blockEnd;
- MemoryHeap *heap = (MemoryHeap*)MMGetDefaultHeap();
- if( heap->FindBlockContaining(start,end, blockStart,blockEnd) )
- if( blockStart==NULL ) {
- MM_WARN("Mem range %p--%p is in heap but not in any block", start,end);
- return kMMFalse;
- } else if( start<blockStart || end>blockEnd ) {
- MM_WARN("Mem range %p--%p violates block %p--%p",
- start,end, blockStart,blockEnd);
- return kMMFalse;
- }
- return kMMTrue;
- }
-
-
- //========================================================================================
- // Block Stack Crawls
- //========================================================================================
-
- MMBoolean
- MMTrackStackCrawls( MMBoolean track )
- {
- MMBoolean old = CBlockStackCrawlHook::gTrack;
- CBlockStackCrawlHook::gTrack = track;
- return old;
- }
-
-
- StackCrawl*
- MMGetBlockStackCrawl( const void *block, long *flags )
- {
- BestFitHeap *heap = GetHeap(block,"MMGetBlockStackCrawl");
- if( heap ) {
- size_t s = (size_t) heap->GetBlockStackCrawl(block);
- if( flags ) *flags = s & 3;
- return (StackCrawl*)( s & ~3L );
- } else {
- if( flags ) *flags = 0;
- return NULL;
- }
- }
-
-
- void
- MMSetBlockStackCrawl( const void *block, StackCrawl *s, long flags )
- {
- BestFitHeap *heap = GetHeap(block,"MMSetBlockStackCrawl");
- if( heap )
- heap->SetBlockStackCrawl( block, (StackCrawl*)( (size_t)s | (flags & 3)) );
- }
-
-
- //========================================================================================
- // Memory Leak Detection
- //========================================================================================
-
-
- struct LeakLink {
- LeakLink* fNext;
- const void* fFirstBlock;
- StackCrawl* fStack;
- unsigned long fCount;
- };
-
- static LeakLink *sLeakLinks;
-
-
- static MMBoolean InitLeaksProc( const void *blk, size_t size, MMBoolean isObject,
- void *refCon )
- {
- // Nuke all previous stack crawls:
- long flags;
- StackCrawl *s = MMGetBlockStackCrawl(blk,&flags);
- if( s ) {
- delete s;
- MMSetBlockStackCrawl(blk,NULL,0);
- }
- return kMMTrue;
- }
-
-
- void
- MMBeginLeakChecking( )
- {
- somPrintf("••• Scanning for memory leaks: please do something 3 or more times.\r");
- MMWalkHeap(NULL,(MMBlockInfoProc) &InitLeaksProc,NULL);
- MMTrackStackCrawls(kMMTrue);
- }
-
-
- extern "C" {
- static MMBoolean FindLeaksProc( const void *blk, size_t size, MMBoolean isObject,
- void *refCon )
- {
- long flags;
- StackCrawl *s = MMGetBlockStackCrawl(blk,&flags);
- if( s ) {
- // This is a new block, check its stack crawl:
- LeakLink *l;
- for( l=sLeakLinks; l; l=l->fNext )
- if( *(l->fStack) == *s ) {
- l->fCount++;
- delete s;
- MMSetBlockStackCrawl(blk,NULL,0);
- return kMMTrue;
- }
- l = new LeakLink;
- l->fNext = sLeakLinks;
- l->fFirstBlock = blk;
- l->fStack = s;
- l->fCount = 1;
- sLeakLinks = l;
- }
- return kMMTrue;
- }
- }
-
- static MMBoolean DumpObjProc( const void *blk, size_t size, MMBoolean isObject,
- void *dumpStack )
- {
- if( isObject ) {
- MMValidateObject((SOMObject*)blk);
- somPrintf(" %p %4lu %s\r", blk,size, ((SOMObject*)blk)->somGetClassName());
- } else if( dumpStack )
- somPrintf(" %p %4lu\r", blk,size);
- if( dumpStack ) {
- StackCrawl *s = MMGetBlockStackCrawl(blk,NULL);
- if( s ) {
- for( long i=0; i<s->CountFrames(); i++ ) {
- char name[256];
- s->GetFrameName(i,name);
- somPrintf(" %s\n",name);
- }
- }
- }
- return true; // Might check for cmd-period or something to abort...
- }
-
- void
- MMEndLeakChecking( )
- {
- MMTrackStackCrawls(kMMFalse);
-
- somPrintf("••• Dumping memory leaks:\r");
- sLeakLinks = NULL;
- MMWalkHeap(NULL,&FindLeaksProc,NULL);
- size_t leakage = 0;
- LeakLink *next;
- for( LeakLink *l=sLeakLinks; l; l=next ) {
- next = l->fNext;
- if( l->fCount >= 3 ) {
- somPrintf("• Leaked %d times:\r", l->fCount);
- size_t size = MMBlockSize(l->fFirstBlock);
- DumpObjProc(l->fFirstBlock,
- size,
- MMIsObject(l->fFirstBlock),
- (void*)kMMTrue);
- leakage += l->fCount * (size+8); // Add 8 bytes for per-block overhead
- }
- delete l->fStack;
- MMSetBlockStackCrawl(l->fFirstBlock,NULL,0);
- delete l;
- }
- sLeakLinks = NULL;
- if( leakage > 0 )
- somPrintf("••• Estimated leakage: %ld bytes\r", leakage);
- else
- somPrintf("••• No leaks found!\r");
- }
-
-
- //========================================================================================
- // Non-Debug Stubs
- //========================================================================================
-
- #else /* MM_DEBUG */
-
-
- void MMBeginMemValidation( ) { }
- void MMEndMemValidation( ) { }
- void MMBeginHeapChecking( ) { }
- void MMEndHeapChecking( ) { }
-
- MMBoolean MMValidatePtr( ConstMMBlock, MMBoolean validateHeap, const char *operation )
- {return 1;}
- MMBoolean MMValidateObject( const SOMObject *o ) {return 1;}
- MMBoolean MMValidateHandle( MMHandle ) {return 1;}
-
- MMBoolean MMDoesHeapExist( MemHeap *heap ) {return 1;}
- MMBoolean MMValidateHeap( MemHeap *heapID, const void* ptr ) {return 1;}
- MMBoolean MMValidateAllHeaps( ) {return 1;}
-
- void MMGetHeapInfo( MemHeap *heapID,
- const char* *name, size_t *allocated, size_t *free,
- size_t *nBlocks, size_t *nObjects ) { }
-
- void MMWalkHeap( MemHeap *heapID, MMBlockInfoProc, void *StackCrawl ) { }
-
- MMBoolean MMFindBlockContaining( const void *, const void*,
- const void* *blockStart, const void* *blockEnd )
- {
- if( blockStart ) *blockStart=NULL;
- return 0;
- }
- MMBoolean MMValidateMemoryRange( const void *start, const void *end ) {return 1;}
-
- MMBoolean MMTrackStackCrawls( MMBoolean ) {return 0;}
- StackCrawl* MMGetBlockStackCrawl( const void *block, long *flags )
- {if( flags ) *flags = 0; return NULL;}
- void MMSetBlockStackCrawl( const void *block, StackCrawl*, long flags ) { }
-
- void MMBeginLeakChecking( void ) { }
- void MMEndLeakChecking( void ) { }
-
-
-
- #endif /*MMDebug*/
-